﻿namespace TomatoBreak.Infrastructure
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;

    public class RESTfulHttpVerbConstraint : IRouteConstraint
    {
        private static readonly IEnumerable<HttpVerbs> knownVerbs = Enum.GetValues(typeof(HttpVerbs)).Cast<HttpVerbs>();

        private readonly IEnumerable<string> acceptVerbs;

        public RESTfulHttpVerbConstraint(HttpVerbs acceptVerbs)
        {
            this.acceptVerbs = ConvertToStringList(acceptVerbs);
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }

            var originalVerb = httpContext.Request.HttpMethod;

            if ((originalVerb != null) &&
                acceptVerbs.Contains(originalVerb, StringComparer.OrdinalIgnoreCase))
            {
                return true;
            }

            var overriddenVerb = httpContext.Request.GetHttpMethodOverride();

            var matched = overriddenVerb != null && acceptVerbs.Contains(overriddenVerb, StringComparer.OrdinalIgnoreCase);

            return matched;
        }

        private static IEnumerable<string> ConvertToStringList(HttpVerbs verb)
        {
            var list = new List<string>();

            Action<HttpVerbs> append = matching =>
            {
               if ((verb & matching) != 0)
               {
                   list.Add(matching.ToString().ToUpperInvariant());
               }
            };

            foreach (var known in knownVerbs)
            {
                append(known);
            }

            return list;
        }
    }
}